package com.glsc.ngateway.ldap.handler;

import com.alibaba.fastjson.JSON;
import com.glsc.ngateway.ldap.exception.BasicException;
import com.glsc.ngateway.ldap.exception.BusinessException;
import com.glsc.ngateway.common.api.ldap.resp.InterfaceReponse;
import com.glsc.ngateway.common.api.common.utils.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@ControllerAdvice
public class GlobalExceptionHanler {


    private Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * @param exception
     * @param request
     * @param response
     * @return
     * @Description 表单验证异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public InterfaceReponse validExceptionHandler(BindException exception, HttpServletRequest request, HttpServletResponse response) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        Map<String, String> errors = new HashMap<>();
        for (FieldError error : fieldErrors) {
            errors.put(error.getField(), error.getDefaultMessage());
        }
        logger.error("抛出表单验证异常：{},时间为：{}" ,JSON.toJSONString(errors), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returRunTimeException(JSON.toJSONString(errors));
    }


    /**
     * @param exception
     * @Description 500异常处理
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public InterfaceReponse errorHandler(Exception exception) {
        for (StackTraceElement trace:exception.getStackTrace()) {
            logger.error(trace.toString());
        }
        logger.error("抛出Exception异常：{},时间为：{}", exception.getClass().getSimpleName(), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returRunTimeException("Exception 异常，异常类为：" + exception.getClass().getSimpleName());
    }

    /**
     * @param basicException
     * @return
     * @Description 运行时错误异常处理
     */
    @ExceptionHandler(value = BasicException.class)
    @ResponseBody
    public InterfaceReponse basicException(BasicException basicException) {
        logger.error("抛出BasicException异常：{},时间为：{}",basicException.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), basicException);
        return InterfaceReponse.returRunTimeException("Runtime Exception 异常，异常类为：" + basicException);
    }


    /**
     * @param exception
     * @return
     * @Description 业务异常
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public InterfaceReponse businessExceptionHandler(BusinessException exception) {
        logger.error("抛出业务异常：{},时间为：{}", exception.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returnException("业务异常，" + exception.getMessage());
    }


    /**
     * @param ex
     * @return
     * @Description 空指针异常。
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public InterfaceReponse nullPointerExceptionHandler(NullPointerException ex) {
        logger.error("抛出NullPointerException异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("NullPoint 异常，异常类为：" + ex.getClass().getSimpleName());
    }

    //类型转换异常

    /**
     * @param ex
     * @return
     * @Description 类型转换异常
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public InterfaceReponse classCastExceptionHandler(ClassCastException ex) {
        logger.error("抛出ClassCastExceptionHandler异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("类型转换异常，异常类为：" + ex.getClass().getSimpleName());
    }

    /**
     * @param ex
     * @return
     * @Description IO Exception
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public InterfaceReponse iOExceptionHandler(IOException ex) {
        logger.error("抛出IOExceptionHandler异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("IOException，异常类为：" + ex.getClass().getSimpleName());
    }


    /**
     * @param ex
     * @return
     * @Description 栈溢出 异常
     */
    @ExceptionHandler(value = StackOverflowError.class)
    @ResponseBody
    public InterfaceReponse stackOverflowErrorHandler(StackOverflowError ex) {
        logger.error("抛出 stackOverflowError异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("StackOverflow 异常，异常类为：" + ex.getClass().getSimpleName());
    }


    /**
     * @param ex
     * @return
     * @Description 未知方法异常
     */
    @ExceptionHandler(value = NoSuchMethodException.class)
    @ResponseBody
    public InterfaceReponse noSuchMethodExceptionHandler(StackOverflowError ex) {
        logger.error("抛出 NoSuchMethodException 异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("NoSuchMethodException 异常，异常类为：" + ex.getClass().getSimpleName());
    }

    /**
     * @param ex
     * @return
     * @Description 数组越界异常
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    @ResponseBody
    public InterfaceReponse indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        ex.printStackTrace();
        logger.error("抛出 IndexOutOfBoundsException 异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("数组越界异常，异常类为：" + ex.getClass().getSimpleName());

    }


    /**
     * 404异常处理
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, NoHandlerFoundException exception, HttpServletResponse response) {
        logger.error("抛出NoHandlerFoundException异常：{},时间为：{}", exception.getClass().getSimpleName(), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returRunTimeException("抛出NoHandlerFoundException异常 异常，异常类为：" + exception.getClass().getSimpleName());
    }

    /**
     * 405异常处理
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, HttpRequestMethodNotSupportedException exception, HttpServletResponse response) {
        logger.error("抛出HttpRequestMethodNotSupportedException异常：{},时间为：{}", exception.getClass().getSimpleName(), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returRunTimeException("抛出HttpRequestMethodNotSupportedException异常，异常类为：" + exception.getClass().getSimpleName());
    }

    /**
     * 415异常处理
     */
    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, HttpMediaTypeNotSupportedException exception, HttpServletResponse response) {
        logger.error("抛出HttpMediaTypeNotSupportedException异常：{},时间为：{}", exception.getClass().getSimpleName(), DateUtil.getCurrentDate(DateUtil.formatSecond), exception);
        return InterfaceReponse.returRunTimeException("415异常，异常类为：" + exception.getClass().getSimpleName());
    }


    /**
     * @param ex
     * @return
     * @Description 400 异常
     */

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public InterfaceReponse httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        logger.error("抛出HttpMessageNotReadableException 异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("抛出HttpMessageNotReadableException，异常类为：" + ex.getClass().getSimpleName());
    }


    /**
     * @Description 400 异常
     * @param ex
     * @return
     */
/*
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public InterfaceReponse requestTypeMismatch(HttpMessageNotReadableException ex) {
        logger.error("抛出 HttpMessageNotReadableException 异常：" +ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        return InterfaceReponse.returnError("400异常，异常类为："+ex.getClass().getSimpleName(),ExceptionConstant.HttpMessageNotReadable,ExceptionConstant.ERROR);
    }
*/


    /**
     * @param ex
     * @return
     * @Description 400 异常
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public InterfaceReponse requestMissingServletRequest(MissingServletRequestParameterException ex) {
        logger.error("抛出 MissingServletRequestParameterException 异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("400异常，异常类为：" + ex.getClass().getSimpleName());
    }


    @ExceptionHandler(value = EmptyResultDataAccessException.class)
    @ResponseBody
    public InterfaceReponse emptyResultDataAccessExceptioneHandler(EmptyResultDataAccessException ex) {
        logger.error("抛出 EmptyResultDataAccessException 异常：{},时间为：{}", ex.toString(), DateUtil.getCurrentDate(DateUtil.formatSecond), ex);
        return InterfaceReponse.returRunTimeException("业务异常，查询结果为NULL");
    }


    /**
     * 对返回数据集中处理
     * @param code
     * @param msg
     * @param ex
     * @param <T>
     * @return
     */
/*
    private <T extends Throwable> RestResponse resultOut(int code, String msg, T ex) {
        ex.printStackTrace();
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return RestResponse.fail(code).msg(msg);
    }
*/

}
